using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;

using MiP.Common;
using MiP.XmlCmd.Shell.Args;
using MiP.XmlCmd.Shell.XmlSource;

namespace MiP.XmlCmd.Shell.Variables
{
    public class VariableSourceParser : IVariableSourceParser
    {
        private readonly IStringVariableParser _stringVariableParser;
        private readonly IXmlSource _xmlSource;
        private readonly ILogger _logger;
        private readonly IXmlVariableParser _xmlVariableParser;

        public VariableSourceParser(IStringVariableParser stringVariableParser, IXmlVariableParser xmlVariableParser, IXmlSource xmlSource, ILogger logger)
        {
            if (stringVariableParser == null)
                throw new ArgumentNullException("stringVariableParser");
            if (xmlSource == null)
                throw new ArgumentNullException("xmlSource");
            if (logger == null)
                throw new ArgumentNullException("logger");
            if (xmlVariableParser == null)
                throw new ArgumentNullException("xmlVariableParser");

            _stringVariableParser = stringVariableParser;
            _xmlSource = xmlSource;
            _logger = logger;
            _xmlVariableParser = xmlVariableParser;
        }

        public IDictionary<string, string> Parse(IEnumerable<VariableSource> sources)
        {
            IDictionary<string, string> result = new Dictionary<string, string>();

            foreach (VariableSource source in sources)
            {
                if (source.IsFile)
                {
                    ParseFromFileName(result, source.Value);
                }
                else
                {
                    ParseFromSetString(result, source.Value);
                }
            }

            return result;
        }

        private void ParseFromFileName(IDictionary<string, string> result, string filename)
        {
            try
            {
                if (!_xmlSource.Exists(filename))
                {
                    _logger.Warn("File does not exist: '{0}'!", filename);
                    return;
                }

                XElement xml = _xmlSource.Load(filename);

                ICollection<KeyValuePair<string, string>> variables = _xmlVariableParser.ParseVariables(xml);

                foreach (KeyValuePair<string, string> pair in variables)
                {
                    if (result.ContainsKey(pair.Key))
                        _logger.Warn("File '{2}': overrides {0}={3} with {0}={1}", pair.Key, pair.Value, filename, result[pair.Key]);

                    result[pair.Key] = pair.Value;
                }
            }
            catch (XmlException ex)
            {
                throw new XmlException(string.Format("Error while parsing file {0}." + Environment.NewLine + ex.Message, filename), ex);
            }
        }


        private void ParseFromSetString(IDictionary<string, string> result, string value)
        {
            KeyValuePair<string, string> pair = _stringVariableParser.Parse(value);
            if (result.ContainsKey(pair.Key))
                _logger.Warn("Argument: overrides {0}={2} with {0}={1}", pair.Key, pair.Value, result[pair.Key]);

            result[pair.Key] = pair.Value;
        }
    }
}